import java.io.*;
import java.net.*;


/**
 * @author Jedrzej Ginter, Adam Pociejowski
 * @version 1.0
 */
public class BadugiServerThread extends Thread {
	private BadugiServer server;
	private Socket playerSocket;
	
	private int playerID;
	private String playerName;

	/**
	 * Constructor of the thread.
	 * @param server Server's socket.
	 * @param playerSocket Player's socket.
	 * @param playerId Player ID.
	 */
	public BadugiServerThread(BadugiServer server, Socket playerSocket, int playerId) {
		super("Player-" + playerId);
		
		this.server = server; 
		this.playerSocket = playerSocket;
		this.playerID = playerId;

		start(); 
	}
	
	
	/**
	 * Main thread's method.
	 * Read requests sending by player.
	 */
	public void run() {
		try {
			DataInputStream reader = new DataInputStream(playerSocket.getInputStream());
			DataOutputStream writer = new DataOutputStream(playerSocket.getOutputStream());
			
			
			writer.writeUTF("numberOfPlayers " + server.numberOfPlayers);
			writer.writeUTF("yourID " + playerID);
			writer.writeUTF("yourCards " + returnPlayerCards());
			writer.writeUTF("yourChips " + server.playerChips[playerID-1]);

			
			while (true) {
				String request = reader.readUTF();
		    	   
				if (request == null) {
					continue;
				}
		    	   
				String[] tab = request.split(" ");
				String cmd = tab[0];


				if (cmd.equalsIgnoreCase("setPlayerName")) {
					writer.writeUTF("yourName " + validatePlayerName(tab[1]));
					
					server.players[playerID-1] = playerName;
					
					server.sendToAll(color("&nbsp; New player: " + bold(playerName), "#00b4ff"));
					server.sendToAll("tableUpdate newPlayer " + playerID + " " + playerName);
					
					String str = "";
					
					for (int i = 0; i < server.numberOfPlayers; i++) {
						if (server.playerStatus[i] == true)
							str += " " + (i+1) + " " + server.players[i];
					}
					
					writer.writeUTF("tableUpdate allCurrentPlayers" + str);
					
					if (server.numberOfCurrentPlayers == server.numberOfPlayers && !server.gameStarted) {
						boolean tmp = true;
						
						for (int i = 0; i < server.numberOfPlayers; i++) {
							if (server.players[i] == null) {
								tmp = false;
								break;
							}
						}
						
						if (tmp)
							server.beginNewGame();
					}
					
				} else if (cmd.equalsIgnoreCase("returnMyCards")) {
					writer.writeUTF("yourCards " + returnPlayerCards());
				
				} else if (cmd.equalsIgnoreCase("returnMyChips")) {
					writer.writeUTF("yourChips " + server.playerChips[playerID-1]);
					
				} else if (cmd.equalsIgnoreCase("numberOfPlayers")) {
					writer.writeUTF("numberOfPlayers " + server.numberOfPlayers);
					
				} else if (cmd.equalsIgnoreCase("dontDrawMyCards")) {
					if (server.registerPlayerMove(playerID, writer, "dontDrawMyCards", null)) {
						checkGameStatus(true);		
					}
					
				} else if (cmd.equalsIgnoreCase("drawMyCards")) {
					if (server.registerPlayerMove(playerID, writer, "drawMyCards", (tab.length-1) + "")) {
						server.drawCards(playerID, request);
						writer.writeUTF("yourCards " + returnPlayerCards());
						
						if (tab.length-1 > 1) {
							server.sendToAll(color("&nbsp; Player " + bold(playerName) + " drew " + (tab.length-1) + " cards.", "#9f9696"));
						} else {
							server.sendToAll(color("&nbsp; Player " + bold(playerName) + " drew 1 card.", "#9f9696"));
						}
						
						checkGameStatus(true);
					}
					
				} else if (cmd.equalsIgnoreCase("check")) {
					if (server.registerPlayerMove(playerID, writer, "check", null)) {
						checkGameStatus(false);
					}
					
				} else if (cmd.equalsIgnoreCase("bet")) {
					if (server.registerPlayerMove(playerID, writer, "bet", tab[1])) {
						checkGameStatus(false);
					}
					
				} else if (cmd.equalsIgnoreCase("raise")) {
					if (server.registerPlayerMove(playerID, writer, "raise", tab[1])) {
						checkGameStatus(false);
					}

				} else if (cmd.equalsIgnoreCase("call")) {
					if (server.registerPlayerMove(playerID, writer, "call", null)) {
						checkGameStatus(false);
					}

				} else if (cmd.equalsIgnoreCase("allIn")) {
					if (server.registerPlayerMove(playerID, writer, "allIn", null)) {
						checkGameStatus(false);
					}

				} else if (cmd.equalsIgnoreCase("fold")) {
					server.registerPlayerMove(playerID, writer, "fold", null);
					server.removeConnection(playerSocket, playerName, playerID);
					checkGameStatus(false);
					
					break;
					
				} else if (cmd.equalsIgnoreCase("nextGameYes")) {
					server.numberOfCurrentPlayers += 1;
					
					server.sendToAll(color("&nbsp; " + bold(playerName) + " wants to play again.", "#c836bb"));
					
					writer.writeUTF("yourCards " + returnPlayerCards());
					writer.writeUTF("yourChips " + server.playerChips[playerID-1]);
					

					if (server.numberOfCurrentPlayers == server.numberOfPlayers) {
						server.beginNewGame();
					}
					
				} else if (cmd.equalsIgnoreCase("nextGameNo")) {
					server.removeConnection(playerSocket, playerName, playerID);
					server.sendToAll("tableUpdate playerGaveUpGame " + playerID + " " + playerName);
					
					if (!server.allowNewPlayers) {
						server.allowNewPlayers = true;
						
						try {
							server.listen();
						} catch (Exception e) {
							System.out.println(" > Cannot listen.");
						}
					}
					
					return;
				}
			}
		} catch (Exception e) {
			if (server.gameStarted) {
				server.registerPseudoFold(playerID, playerName);
			} else {
				server.numberOfCurrentPlayers -= 1;
			}
			
			
			server.removeConnection(playerSocket, playerName, playerID);
			
			
			if (server.gameStarted) {
				server.sendToAll("tableUpdate fold " + playerID);
				
				int nextPlayerID = server.nextPlayer(playerID);
				String[] roundStatus = server.isEndOf(nextPlayerID);
				
				if (roundStatus[0].equals("true")) {
					if (roundStatus[1].equals("true")) {
						
						server.chooseWinner();
	
					} else {
						server.sendToAll("endOfRound " + roundStatus[2]);
						server.sendToAll("newRound " + (Integer.parseInt(roundStatus[2])+1));
					}
				}
			}
		}
		
		return;
	}
	
	
	/**
	 * Method checks current game/ round is over.
	 * @param isDrawingRound If current round is a round for drawing cards.
	 */
	private void checkGameStatus(boolean isDrawingRound) {
		if (isDrawingRound) {
			String[] roundStatus = server.isEndOf(0);
	        
			if (roundStatus[0].equals("true")) {
				if (roundStatus[1].equals("true")) {
	                        
					server.chooseWinner();
	                        
				} else {
					server.sendToAll("endOfRound " + roundStatus[2]);
					server.sendToAll("newRound " + (Integer.parseInt(roundStatus[2])+1));
					server.sendToAll("nextPlayerMove " + server.smallBlindHolder + " " + server.players[server.smallBlindHolder-1] + " " + server.possiblePlayerMoves(server.smallBlindHolder));
				}
	        }   
		} else {
			int nextPlayerID = server.nextPlayer(playerID);
			String[] roundStatus = server.isEndOf(nextPlayerID);
			
			
			if (roundStatus[0].equals("true")) {
				if (roundStatus[1].equals("true")) {
					
					server.chooseWinner();

				} else {
					server.sendToAll("endOfRound " + roundStatus[2]);
					server.sendToAll("newRound " + (Integer.parseInt(roundStatus[2])+1));
				}
			} else {
				server.sendToAll("nextPlayerMove " + nextPlayerID + " " + server.players[nextPlayerID-1] + " " + server.possiblePlayerMoves(nextPlayerID));
			}
		}
	}
	
	
	/**
	 * @return String containing 4 substrings (player cards in format: VALUE-COLOR, for ex.:
	 * 8-Black-Spade).
	 */
	private String returnPlayerCards() {
		String cards = "";
		int firstCardIndex = (playerID - 1) * 4;
			
		for (int i = firstCardIndex; i <= firstCardIndex + 3; i++) {
			cards += server.playerCards[i] + " ";
		}
		
		return cards;
	}
	
	
	/**
	 * Checks if player name is unique.
	 * @param name Player name to check.
	 * @return Validated player name. If is unique method returns input string, if not, String
	 * which is unique player name.
	 */
	private String validatePlayerName(String name) {
		try {

			if (name == null || name.equalsIgnoreCase("null")) {
				name = "Player-" + playerID;
			} else {
				boolean tmp = true;
				
				while (tmp) {
					tmp = false;
					
					for (int i = 0; i < server.numberOfPlayers; i++) {
						if (name.equals(server.players[i])) {
							name += "-1";
							tmp = true;
						}
					}
				}
			}

		} catch (Exception e) {
			name = "Player-" + playerID;
		}
		
		playerName = name;
		return name;
	}
	
	
	/**
	 * @param str String to bold.
	 * @return String with HTML brackets (b).
	 */
	private String bold(String str) {
		return "<b>" + str + "</b>";
	}
	
	
	/**
	 * @param str Input string.
	 * @param color Color (for ex.: orange, yellow or #000000).
	 * @return A string with HTML brackets (span) with in-line style.
	 */
	private String color(String str, String color) {
		return "<span style=\"color:" + color + ";\">" + str + "</span>";
	}
}